package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.minio.MinioConfiguration;
import com.atguigu.lease.common.minio.MinioProperties;
import com.atguigu.lease.web.admin.service.FileService;
import io.minio.*;
import io.minio.errors.*;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

//使用前要导入minio依赖(不是场景启动器)在common包里
@Service
public class FileServiceImpl implements FileService {

    //提取出minio相关参数方便管理/解耦
    @Autowired
    private MinioProperties properties;

    //将MinioClient初始化放在Bean里,而不是每次上传图片都重新登录
    @Autowired
    private MinioClient client;

    @Override
    public String upload(MultipartFile file) throws Exception {
        //1.判断bucket是否存在
        boolean bucketExists = client.bucketExists(BucketExistsArgs
                .builder()
                .bucket(properties.getBucketName())
                .build());

        //如果不存在则创建一个bucket
        if (!bucketExists) {
            //创建bucket
            client.makeBucket(MakeBucketArgs
                    .builder()
                    .bucket(properties.getBucketName())
                    .build());
            //设置bucket访问策略
            client.setBucketPolicy(SetBucketPolicyArgs
                    .builder()
                    .bucket(properties.getBucketName())
                    .config(createBucketPolicyConfig(properties.getBucketName()))
                    .build());
        }


        //2.设置图片在MinIO中的名字,为了防止上传的图片原始名字相同,后面图片覆盖前面图片,使用"UUID-原始名"
        String filename = UUID.randomUUID() + "-" + file.getOriginalFilename();
        //也可以带文件夹方式: yyyyMMdd/HH/UUID-原始名,会将图片"UUID-原始名"放到"yyyyMMdd/HH"文件夹下
        String time = new SimpleDateFormat("yyyyMMdd/HH").format(new Date());
        filename = time + "/" + filename;

        //3.将图片上传
        //putObject()是上传运行内存的文件,uploadObject()是上传本地已有的文件
        client.putObject(PutObjectArgs.builder()
                .bucket(properties.getBucketName())//设置图片上传到哪个bucket中
                .object(filename)//设置图片在MinIO中的名字
                //stream三个参数:
                // 文件的输入流
                // 文件字节大小
                // 文件拆分方式(-1表示由minio自动拆分,0表示不拆分,也可以指定拆分大小)
                .stream(file.getInputStream(), file.getSize(), -1)//将图片转成流进行上传
                .contentType(file.getContentType())
                .build());//获取文件的MIME类型,并添加到MinIO中

        //4.拼接返回值
        //MinIO的API没有返回url的方法,只能自己写轮子,可以直接拼,也可以用方法join;join方法用的是StringBuilder,参数是可变参考
        //String url = properties.getEndpoint() + "/" + properties.getBucketName() + "/" + filename;
        //return url;
        return String.join("/", properties.getEndpoint(), properties.getBucketName(), filename);

    }

    private String createBucketPolicyConfig(String bucketName) {
        return """
            {
              "Statement" : [ {
                "Action" : "s3:GetObject",
                "Effect" : "Allow",
                "Principal" : "*",
                "Resource" : "arn:aws:s3:::%s/*"
              } ],
              "Version" : "2012-10-17"
            }
            """.formatted(bucketName);
    }
}
